export = {};
interface Person {
  name: string;
  age: number;
}
let person: Person = {
  name: 'Jarid',
  age: 35
};
/** T[K]， 索引访问操作符. indexed access operator*/
/*
The second operator is T[K], the indexed access operator. Here, the type syntax reflects the expression syntax.
That means that person['name'] has the type Person['name'] — which in our example is just string.
However, just like index type queries, you can use T[K] in a generic context, which is where its real power comes to life.
You just have to make sure that the type variable K extends keyof T.
Here’s another example with a function named getProperty.
*/
//  在这里，类型语法反映了表达式语法。
//  这意味着 person['name']具有类型 Person['name'] — 在我们的例子里则为 string类型。
//  然而，就像索引类型查询一样，你可以在泛型的上下文里使用 T[K]，这正是它的强大所在。
//  你只要确保类型变量 K extends keyof T就可以了。 例如下面 getProperty函数的例子：
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
  return o[name]; // o[name] is of type T[K]
}
/*
In getProperty, o: T and propertyName: K, so that means o[propertyName]: T[K]. Once you return the T[K] result, the compiler will instantiate the actual type of the key, so the return type of getProperty will vary according to which property you request.
*/
//getProperty里的 o: T和 name: K，意味着 o[name]: T[K]。
// 当你返回 T[K]的结果，编译器会实例化键的真实类型，因此 getProperty的返回值类型会随着你需要的属性改变。
let name: string = getProperty(person, 'name');
let age: number = getProperty(person, 'age');
let unknown = getProperty(person, 'unknown'); // error, 'unknown' is not in 'name' | 'age'
